package com.tiancheng.trade.payment.channel.fudian;

import com.tiancheng.commom.pay.PayOrderAutoQueryConfig;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.commom.web.feign.MerchantFeignService;
import com.tiancheng.trade.commom.web.http.PlatformRequest;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.payment.channel.AbstractPayChannel;
import com.tiancheng.trade.payment.channel.bo.*;
import com.tiancheng.trade.payment.channel.fudian.params.FudianAuthorization;
import com.tiancheng.trade.payment.channel.fudian.params.FudianCommon;
import com.tiancheng.trade.payment.channel.fudian.params.FudianUnifiedOrderParam;
import com.tiancheng.trade.payment.channel.fudian.util.FudianSignUtil;
import com.tiancheng.trade.commom.core.enums.PaySceneEnum;
import com.tiancheng.trade.commom.core.enums.PaymentChannelEnum;
import com.tiancheng.trade.commom.core.enums.PaymentWayEnum;
import com.tiancheng.trade.commom.web.model.request.MerchantChannelRequestDTO;
import com.tiancheng.trade.commom.web.model.response.MerchantChannelResponseDTO;
import com.tiancheng.trade.payment.model.PaymentFlowDetailSettle;
import com.tiancheng.trade.payment.model.PaymentFlowDetailSettleDetail;
import com.tiancheng.trade.payment.util.EnumUtil;
import com.tiancheng.trade.payment.util.JacksonJsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 富滇支付渠道
 *
 * @author kellen
 * @date 2024/4/10
 */
@Slf4j
@Service
public class FudianPayChannel implements AbstractPayChannel {

    @Resource
    private JacksonJsonUtil jacksonJsonUtil;
    @Resource
    private PlatformRequest platformRequest;
    @Resource
    private MerchantFeignService merchantFeignService;

    @Value(value = "${channel.fudian.payCallback}")
    private String payCallback;
    @Value(value = "${channel.fudian.domain}")
    private String fudianDomain;

    @Override
    public PaymentChannelEnum getPaymentChannelEnum() {
        return PaymentChannelEnum.FUDIAN;
    }

    @Override
    public Result<UnifiedOrderResBO> unifiedOrder(UnifiedOrderBO unifiedOrderBO) throws BusinessException {
        String timeStamp = String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());

        // 调用商户中心，查询商户的渠道进件编号
        Map<String, String> merchantMap = new HashMap<>();
        unifiedOrderBO.getSubOrders().forEach(subOrderBO -> merchantMap.put(subOrderBO.getMerchantCode(),
                PaymentChannelEnum.FUDIAN.getCode()));
        merchantMap.put(unifiedOrderBO.getMerchantCode(), PaymentChannelEnum.FUDIAN.getCode());     //主商户
        List<MerchantChannelRequestDTO> merchantChannelRequestDTOS = merchantMap.entrySet().stream().map(entry ->
                new MerchantChannelRequestDTO(entry.getKey(), entry.getValue(),unifiedOrderBO.getOrgPaymentChannelId(),unifiedOrderBO.getBusinessCode())).collect(Collectors.toList());

        Result<List<MerchantChannelResponseDTO>> merchantChannelResult = merchantFeignService.findSubAppidList(merchantChannelRequestDTOS);
        BusinessErrorInfoEnum.CHANNEL_PAY_NO_MERCHANT.assertIsTrue(
                merchantChannelResult.getRet() == 0 && merchantChannelResult.getData().size() == merchantMap.size());
        merchantChannelResult.getData().forEach(r -> merchantMap.put(r.getMerchantCode(), r.getSubAppid()));

        FudianCommon common = new FudianCommon();
        common.setIp("14.204.115.37");
        common.setAddress("昆明市");
        common.setLocation("102.832033,24.951908");

        FudianUnifiedOrderParam.Body body = new FudianUnifiedOrderParam.Body();
        body.setMerchantId(merchantMap.get(unifiedOrderBO.getMerchantCode()));
        body.setBusinessOrderId(unifiedOrderBO.getOrderId());
        body.setTotalAmount(BigDecimal.valueOf(unifiedOrderBO.getAmount()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP).toString());
        body.setCreateUser(unifiedOrderBO.getUid());
        body.setOrderSource(9);
        body.setNotifyUrl(payCallback);
        body.setSubGeneralList(new ArrayList<>());
        body.setBuyerId(unifiedOrderBO.getOpenid());

        // 确认支付类型
        body.setPayType(2);     //默认统一下单类型
        if (unifiedOrderBO.getPayWay().equals(PaymentWayEnum.WECHAT.getCode())) {
            switch (EnumUtil.getEnumByCode(PaySceneEnum.class, unifiedOrderBO.getPayScene())) {
                case H5:
                    body.setPayType(8);
                    break;
                case MINIAPP:
                    body.setPayType(9);
                    break;
            }
        } else if (unifiedOrderBO.getPayWay().equals(PaymentWayEnum.ALIPAY.getCode())) {
            switch (EnumUtil.getEnumByCode(PaySceneEnum.class, unifiedOrderBO.getPayScene())) {
                case H5:
                    body.setPayType(11);
                    break;
            }
        } else if (unifiedOrderBO.getPayWay().equals(PaymentWayEnum.UNIONPAY.getCode())) {
            body.setPayType(12);
        }

        unifiedOrderBO.getSubOrders().forEach(subOrderBO -> {
            FudianUnifiedOrderParam.SubStore subStore = new FudianUnifiedOrderParam.SubStore();
            subStore.setBusinessOrderId(subOrderBO.getSubOrderId());
            subStore.setMerchantId(merchantMap.get(subOrderBO.getMerchantCode()));
            subStore.setProductName(subOrderBO.getProductName());
            subStore.setTotalAmount(BigDecimal.valueOf(subOrderBO.getAmount()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP).toString());
            subStore.setPrice(subStore.getTotalAmount());
            subStore.setNum(1);
            body.getSubGeneralList().add(subStore);
        });
        String sign = FudianSignUtil.createSign(timeStamp, jacksonJsonUtil.fromJson(JsonUtil.toJsonString(body), TreeMap.class));

        FudianAuthorization authorization = new FudianAuthorization();
        authorization.setSign(sign);
        authorization.setTimeStamp(timeStamp);

        FudianUnifiedOrderParam unifiedOrder = new FudianUnifiedOrderParam();
        unifiedOrder.setAuthorization(authorization);
        unifiedOrder.setCommon(common);
        unifiedOrder.setBody(body);

        String url = fudianDomain + "/travelApi/order/createGeneralOrder";
        log.info("fudian_unifiedOrder_url:{}, params:{}", url, JsonUtil.toJsonString(unifiedOrder));
        Result result = platformRequest.jsonPostRequest(url,  unifiedOrder, false, null);
        log.info("fudian_pay_result: {}", result);

        Map<String, Object> resultMap = JsonUtil.fromJson(result.toString(), Map.class);
        Map<String, Object> dataMap = (Map) resultMap.get("data");

        String orderId = dataMap.get("orderId").toString();

        Result<UnifiedOrderResBO> payResult = new Result<>();
        payResult.setRet(result.getRet());
        payResult.setErrorCode(result.getErrorCode());
        payResult.setMsg(result.getMsg());
        payResult.setData(new UnifiedOrderResBO(orderId, unifiedOrderBO.getOrderId(), JsonUtil.toJsonString(dataMap.get("payInfo")), null));

        // todo 获取富滇的收银台跳转页面地址，暂时不用
//        FudianGetPayUrlParam.Body getBody = new FudianGetPayUrlParam.Body();
//        getBody.setOrderId(orderId);
//        // 设置支付成功的后置页面
//        getBody.setRedirectUrl(unifiedOrderBO.getEndPage());
//
//        sign = FudianSignUtil.createSign(timeStamp, jacksonJsonUtil.fromJson(JsonUtil.toJsonString(getBody), TreeMap.class));
//        authorization.setSign(sign);
//
//        FudianGetPayUrlParam getPayUrlParam = new FudianGetPayUrlParam();
//        getPayUrlParam.setAuthorization(authorization);
//        getPayUrlParam.setCommon(common);
//        getPayUrlParam.setBody(getBody);
//
//        String getUrl = fudianDomain + "/travelApi/order/getOnePayUrl";
//        result = wiiRequest.jsonPostRequest(getUrl, null, getPayUrlParam, false, null);
//        log.info("getUrl result: {}", result);
//
//        Map<String, Object> getUrlMap = JsonUtil.fromJson(result.toString(), Map.class);
//        Map<String, Object> getUrlDataMap = (Map<String, Object>) getUrlMap.get("data");
//        String payUrl = getUrlDataMap.get("payUrl").toString();
//
//        Result<UnifiedOrderResBO> payResult = new Result<>();
//        payResult.setRet(result.getRet());
//        payResult.setErrorcode(result.getErrorcode());
//        payResult.setMsg(result.getMsg());
//        payResult.setData(new UnifiedOrderResBO(orderId, unifiedOrderBO.getOrderId(), payUrl));

        return payResult;
    }

    @Override
    public Result<GetUnifiedOrderResBO> get(GetUnifiedOrderBO getUnifiedOrderBO) throws BusinessException {
        return null;
    }

    @Override
    public Result<RefundOrderResBO> refund(RefundOrderBO refundOrderBO) throws BusinessException {
        return null;
    }

    @Override
    public Result<GetRefundOrderResBO> getRefund(GetRefundOrderBO getRefundOrderBO) throws BusinessException {
        return null;
    }

    @Override
    public Result close(CloseOrderBO closeOrderBO) throws BusinessException {
        return null;
    }

    @Override
    public PayResultBO payResult(Map<String, Object> payResult) {
        Map<String, Object> bodyMap = (Map<String, Object>) payResult.get("body");

        PayResultBO payResultBO = new PayResultBO();
        payResultBO.setUid(String.valueOf(bodyMap.get("createUser")));
        payResultBO.setOrderId(String.valueOf(bodyMap.get("businessOrderId")));
        payResultBO.setTransactionId(String.valueOf(bodyMap.get("orderId")));
        payResultBO.setTradeNo(String.valueOf(bodyMap.get("payOrderNo")));
        payResultBO.setPayTime(DateTimeUtil.string2LocalDateTime(String.valueOf(bodyMap.get("createTime")), "yyyy-MM-dd HH:mm:ss"));
        payResultBO.setStatus("1".equals(String.valueOf(bodyMap.get("payStatus"))) ? "success" : "fail");

        BigDecimal payActAmount = new BigDecimal(String.valueOf(bodyMap.get("payActAmount")));
        payResultBO.setAmount(payActAmount.multiply(new BigDecimal(100)).intValue());
        // TODO 根据实际情况修改优惠金额
        payResultBO.setCouponAmount(0);
        return payResultBO;
    }

    @Override
    public RefundResultBO refundResult(Map<String, Object> refundResult) {
        return null;
    }

    @Override
    public Result settleV2(List<PaymentFlowDetailSettle> detailSettles, List<PaymentFlowDetailSettleDetail> detailSettlesDetails) throws BusinessException {
        return null;
    }

    @Override
    public boolean autoQueryStatus(Long orgPaymentChannelId) {
        return false;
    }

    @Override
    public PayOrderAutoQueryConfig getOrderAutoQueryConfig(Long orgPaymentChannelId) {
        return null;
    }
}
